using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;

namespace Grafica1
{
    public interface ICameraService
    {
        Camera CurrentCamera { get; }
        bool Enable { get; set; }
    }

    /// <summary>
    /// This is a game component that implements ICameraService_.
    /// </summary>
    public class CameraManager : Microsoft.Xna.Framework.GameComponent, ICameraService
    {
        public const float MOVING_SPEED = 20;
        public const float ROTATION_SPEED = 0.12f * MathHelper.Pi;
        public const float SPEED_INCREMENT = 1.333f;
        public const float TOP_SPEED = 400;
        public const float LOWER_SPEED = 5;

        private Camera _CurrentCamera;
        private float _moovingSpeed = MOVING_SPEED;
        private float _rotatingSpeed = ROTATION_SPEED;
        private KeyboardState _old = new KeyboardState();
        public Camera _leftViewPoint;
        public Camera _rightViewPoint;

        private bool _Enable = true;

        public bool Enable { get { return _Enable; } set { _Enable = value; } }

        public Camera CurrentCamera
        {
            get { return _CurrentCamera; }
            private set { _CurrentCamera = value; }
        }


        public CameraManager(Game game)
            : base(game)
        {
            game.Services.AddService(typeof(ICameraService), this);
            _leftViewPoint = new Camera(Vector3.Zero, Quaternion.Identity, Camera.DEFAULT_FIELD_OF_VIEW, Camera.DEFAULT_ASPECT_RATIO);
            _leftViewPoint.Name = "Left Camera";


            _rightViewPoint = new Camera(Vector3.Zero, Quaternion.Identity, Camera.DEFAULT_FIELD_OF_VIEW, Camera.DEFAULT_ASPECT_RATIO);
            _rightViewPoint.Name = "Right Camera";

            _CurrentCamera = _leftViewPoint;

        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            //build the defaultCamera



            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here

            var now = Keyboard.GetState();

            ProcessNecessaryInput(now);
            if (_Enable)
            {
                ProcessInput(now, gameTime);
            }

            _old = now;

            base.Update(gameTime);
        }

        private void ProcessNecessaryInput(KeyboardState state)
        {

        }

        private void ProcessInput(KeyboardState state, GameTime gameTime)
        {
            float dt = ((float)gameTime.ElapsedGameTime.Milliseconds) / 1000.0f * _moovingSpeed;
            float dr = ((float)gameTime.ElapsedGameTime.Milliseconds) / 1000.0f * _rotatingSpeed;
            float dPlane = 0.1f;

            var keys = state.GetPressedKeys();

            foreach (var key in keys)
            {
                var trans = Matrix.Transpose(_CurrentCamera.View);
                switch (key)
                {
                    case Keys.W:
                        _CurrentCamera.position = Vector3.Transform(_CurrentCamera.position, Matrix.CreateTranslation(trans.Forward * dt));
                        break;
                    case Keys.S:
                        _CurrentCamera.position = Vector3.Transform(_CurrentCamera.position, Matrix.CreateTranslation(trans.Backward * dt));
                        break;
                    case Keys.D:
                        _CurrentCamera.position = Vector3.Transform(_CurrentCamera.position, Matrix.CreateTranslation(trans.Right * dt));
                        break;
                    case Keys.A:
                        _CurrentCamera.position = Vector3.Transform(_CurrentCamera.position, Matrix.CreateTranslation(trans.Left * dt));
                        break;
                    case Keys.X:
                        _CurrentCamera.position = Vector3.Transform(_CurrentCamera.position, Matrix.CreateTranslation(trans.Down * dt));
                        break;
                    case Keys.Space:
                        _CurrentCamera.position = Vector3.Transform(_CurrentCamera.position, Matrix.CreateTranslation(trans.Up * dt));
                        break;
                    case Keys.Up:
                        _CurrentCamera.orientation = Quaternion.Concatenate(_CurrentCamera.orientation, Quaternion.CreateFromAxisAngle(trans.Left, dr));
                        break;
                    case Keys.Down:
                        _CurrentCamera.orientation = Quaternion.Concatenate(_CurrentCamera.orientation, Quaternion.CreateFromAxisAngle(trans.Right, dr));
                        break;
                    case Keys.LeftAlt:
                        _CurrentCamera.orientation = Quaternion.Concatenate(_CurrentCamera.orientation, Quaternion.CreateFromAxisAngle(trans.Forward, dr));
                        break;
                    case Keys.LeftControl:
                        _CurrentCamera.orientation = Quaternion.Concatenate(_CurrentCamera.orientation, Quaternion.CreateFromAxisAngle(trans.Backward, dr));
                        break;
                    case Keys.Right:
                        _CurrentCamera.orientation = Quaternion.Concatenate(_CurrentCamera.orientation, Quaternion.CreateFromAxisAngle(trans.Down, dr));
                        break;
                    case Keys.Left:
                        _CurrentCamera.orientation = Quaternion.Concatenate(_CurrentCamera.orientation, Quaternion.CreateFromAxisAngle(trans.Up, dr));
                        break;
                    case Keys.F1:
                        if (_CurrentCamera.fieldOfView + MathHelper.Pi / 1000 < MathHelper.Pi)
                            _CurrentCamera.fieldOfView += MathHelper.Pi / 1000;
                        break;
                    case Keys.F2:
                        if (_CurrentCamera.fieldOfView - MathHelper.Pi / 1000 > 0)
                            _CurrentCamera.fieldOfView -= MathHelper.Pi / 1000;
                        break;
                    case Keys.N:
                        if (_CurrentCamera.NearPlane - dPlane > 0.001)
                            _CurrentCamera.NearPlane -= dPlane;
                        break;
                    case Keys.M:
                        if (_CurrentCamera.NearPlane + dPlane < _CurrentCamera.FarPlane)
                            _CurrentCamera.NearPlane += dPlane;
                        break;
                    case Keys.J:
                        if (_CurrentCamera.FarPlane - dPlane > _CurrentCamera.NearPlane)
                            _CurrentCamera.FarPlane -= dPlane;
                        break;
                    case Keys.K:
                        if (_CurrentCamera.FarPlane + dPlane < 100000.0f)
                            _CurrentCamera.FarPlane += dPlane;
                        break;
                    case Keys.RightControl:
                        if (_moovingSpeed >= LOWER_SPEED)
                            _moovingSpeed -= SPEED_INCREMENT;
                        break;
                    case Keys.RightShift:
                        if (_moovingSpeed <= TOP_SPEED)
                            _moovingSpeed += SPEED_INCREMENT;
                        break;

                    case Keys.PageUp:
                        if (!_old.IsKeyDown(Keys.PageUp))
                        {
                            if (_CurrentCamera == _leftViewPoint)
                            {
                                _CurrentCamera = _rightViewPoint;
                            }
                            else
                            {
                                _CurrentCamera = _leftViewPoint;
                            }
                        }
                        break;
                    case Keys.PageDown: if (!_old.IsKeyDown(Keys.PageDown))
                        {
                            if (_CurrentCamera == _leftViewPoint)
                            {
                                _CurrentCamera = _rightViewPoint;
                            }
                            else
                            {
                                _CurrentCamera = _leftViewPoint;
                            }
                        }
                        break;
                    default: break;
                }
            }
        }
    }

   
        //public bool isActive()
        //{
        //    return
        //        whereIAm.isInitialized() &&
        //        whereToGo.isInitialized() &&
        //        !whereIAm.Equals(whereToGo);
        //}

        //private void stimate()
        //{

        //    cinematicPassed = 0;

        //    fromEye = Vector3.Transform(-whereIAm.View.Translation, Matrix.Transpose(whereIAm.View));
        //    toEye = Vector3.Transform(-whereToGo.View.Translation, Matrix.Transpose(whereToGo.View));

        //    var c = whereIAm.View * Matrix.CreateTranslation(-whereIAm.View.Translation);
        //    var toRot = whereToGo.View * Matrix.CreateTranslation(-whereToGo.View.Translation);

        //    Vector3 a, b;
        //    Matrix.Transpose(c).Decompose(out a, out fromQuat, out b);
        //    Matrix.Transpose(toRot).Decompose(out a, out toQuat, out b);

        //    fromField = whereIAm.FieldOfView;
        //    toField = whereToGo.FieldOfView;

        //    whereIAm.Name = "Moving to " + whereToGo.Name;
        //}
}
